package web

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"x-admin-generator/internal/config"
	"x-admin-generator/internal/database"
	"x-admin-generator/internal/generator"
	"x-admin-generator/internal/types"
)

// StartWebServer 启动Web配置界面
func StartWebServer() {
	fmt.Println("\n🌐 启动Web配置界面...")
	fmt.Println(strings.Repeat("=", 40))

	// 设置路由
	http.HandleFunc("/", serveWebInterface)
	http.HandleFunc("/api/save-config", handleSaveConfig)
	http.HandleFunc("/api/generate", handleWebGenerate)
	http.HandleFunc("/api/models", handleListWebModels)
	http.HandleFunc("/api/import-table", handleImportTable)
	http.HandleFunc("/api/config/", handleGetConfig)

	port := "8081"
	fmt.Printf("🚀 Web界面已启动: http://localhost:%s\n", port)
	fmt.Println("💡 在浏览器中打开上述地址开始配置")
	fmt.Println("⚠️  按 Ctrl+C 停止服务器")

	if err := http.ListenAndServe(":"+port, nil); err != nil {
		fmt.Printf("❌ 启动Web服务器失败: %v\n", err)
	}
}

// serveWebInterface 提供Web界面
func serveWebInterface(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.ServeFile(w, r, "web/index.html")
	} else if r.URL.Path == "/app.js" {
		http.ServeFile(w, r, "web/app.js")
	} else {
		http.NotFound(w, r)
	}
}

// handleSaveConfig 处理保存配置请求
func handleSaveConfig(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var modelConfig types.ModelConfig
	if err := json.NewDecoder(r.Body).Decode(&modelConfig); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// 保存配置文件
	configPath := config.GetConfigPath(fmt.Sprintf("%s.yaml", strings.ToLower(modelConfig.Model.Name)))
	if err := config.SaveModelConfig(configPath, &modelConfig); err != nil {
		http.Error(w, fmt.Sprintf("Save failed: %v", err), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]string{"status": "success"})
}

// handleWebGenerate 处理Web生成请求
func handleWebGenerate(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var modelConfig types.ModelConfig
	if err := json.NewDecoder(r.Body).Decode(&modelConfig); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// 先保存配置
	configPath := config.GetConfigPath(fmt.Sprintf("%s.yaml", strings.ToLower(modelConfig.Model.Name)))
	if err := config.SaveModelConfig(configPath, &modelConfig); err != nil {
		http.Error(w, fmt.Sprintf("Save config failed: %v", err), http.StatusInternalServerError)
		return
	}

	// 生成代码
	if err := generator.SetupTempDirectory(); err != nil {
		http.Error(w, fmt.Sprintf("Setup temp directory failed: %v", err), http.StatusInternalServerError)
		return
	}

	generator.GenerateModelToTemp(modelConfig.Model.Name)

	// 计算生成的文件数量
	fileCount := 0
	tempDir := config.GetTempDir()
	filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() {
			fileCount++
		}
		return nil
	})

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"status":    "success",
		"fileCount": fileCount,
	})
}

// handleListWebModels 处理获取模型列表请求
func handleListWebModels(w http.ResponseWriter, r *http.Request) {
	cfg := config.GetConfig()
	configDir := cfg.Paths.ModelsConfig
	files, err := filepath.Glob(filepath.Join(configDir, "*.yaml"))
	if err != nil {
		http.Error(w, fmt.Sprintf("Read config directory failed: %v", err), http.StatusInternalServerError)
		return
	}

	var models []string
	for _, file := range files {
		modelName := strings.TrimSuffix(filepath.Base(file), ".yaml")
		models = append(models, modelName)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(models)
}

// handleImportTable 处理从数据库导入表结构
func handleImportTable(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var request struct {
		Table string `json:"table"`
	}

	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// 获取数据库配置
	dbConfig := config.GetDatabaseConfig()

	// 连接数据库
	db, err := database.Connect(dbConfig)
	if err != nil {
		http.Error(w, fmt.Sprintf("Database connection failed: %v", err), http.StatusInternalServerError)
		return
	}
	defer db.Close()

	// 获取表信息
	tableInfo, err := database.GetTableInfo(db, dbConfig.Database, request.Table)
	if err != nil {
		http.Error(w, fmt.Sprintf("Get table info failed: %v", err), http.StatusInternalServerError)
		return
	}

	// 转换为模型配置
	modelConfig := convertTableToModelConfig(tableInfo)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(modelConfig)
}

// handleGetConfig 处理获取指定配置
func handleGetConfig(w http.ResponseWriter, r *http.Request) {
	// 从URL路径中提取模型名称
	path := strings.TrimPrefix(r.URL.Path, "/api/config/")
	modelName := strings.TrimSuffix(path, "/")

	if modelName == "" {
		http.Error(w, "Model name required", http.StatusBadRequest)
		return
	}

	// 读取配置文件
	configPath := config.GetConfigPath(fmt.Sprintf("%s.yaml", strings.ToLower(modelName)))
	modelConfig, err := config.LoadModelConfig(configPath)
	if err != nil {
		http.Error(w, fmt.Sprintf("Load config failed: %v", err), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(modelConfig)
}

// convertTableToModelConfig 将数据库表信息转换为模型配置
func convertTableToModelConfig(tableInfo *types.TableInfo) *types.ModelConfig {
	fields := make([]types.Field, 0, len(tableInfo.Columns))
	
	for _, column := range tableInfo.Columns {
		field := types.Field{
			Name:     column.Name,
			Type:     database.ConvertMySQLTypeToGo(column.Type),
			Required: !column.Nullable,
			Primary:  column.Key == "PRI",
			Comment:  column.Comment,
		}
		fields = append(fields, field)
	}

	return &types.ModelConfig{
		Model: types.Model{
			Name:    strings.Title(tableInfo.Name),
			Table:   tableInfo.Name,
			Comment: tableInfo.Comment,
			Fields:  fields,
		},
	}
}